home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / muds / lpmud312.tar / lpmud312 / call_out.c < prev    next >
C/C++ Source or Header  |  1991-10-31  |  8KB  |  308 lines

  1. #include <setjmp.h>
  2. #include <memory.h>
  3. #include <string.h>
  4.  
  5. #include "lint.h"
  6. #include "interpret.h"
  7. #include "object.h"
  8.  
  9. /*
  10.  * This file implements delayed calls of functions.
  11.  * Static functions can not be called this way.
  12.  *
  13.  * Allocate the structures several in one chunk, to get rid of malloc
  14.  * overhead.
  15.  */
  16.  
  17. #define CHUNK_SIZE    20
  18.  
  19. extern char *xalloc(), *string_copy();
  20. extern jmp_buf error_recovery_context;
  21. extern int error_recovery_context_exists;
  22.  
  23. struct call {
  24.     int delta;
  25.     char *function;
  26.     struct object *ob;
  27.     struct svalue v;
  28.     struct call *next;
  29.     struct object *command_giver;
  30. };
  31.  
  32. static struct call *call_list, *call_list_free;
  33. static int num_call;
  34.  
  35. /*
  36.  * Free a call out structure.
  37.  */
  38. static void free_call(cop)
  39.     struct call *cop;
  40. {
  41.     free_svalue(&cop->v);
  42.     cop->next = call_list_free;
  43.     free(cop->function);
  44.     cop->function = 0;
  45.     free_object(cop->ob, "free_call");
  46.     if (cop->command_giver)
  47.     free_object(cop->command_giver, "free_call");
  48.     cop->ob = 0;
  49.     call_list_free = cop;
  50. }
  51.  
  52. /*
  53.  * Setup a new call out.
  54.  */
  55. void new_call_out(ob, fun, delay, arg)
  56.     struct object *ob;
  57.     char *fun;
  58.     int delay;
  59.     struct svalue *arg;
  60. {
  61.     struct call *cop, **copp;
  62.  
  63.     if (delay < 1)
  64.     delay = 1;
  65.     if (!call_list_free) {
  66.     int i;
  67.     call_list_free =
  68.         (struct call *)xalloc(CHUNK_SIZE * sizeof (struct call));
  69.     for (i=0; i<CHUNK_SIZE - 1; i++)
  70.         call_list_free[i].next  = &call_list_free[i+1];
  71.     call_list_free[CHUNK_SIZE-1].next = 0;
  72.     num_call += CHUNK_SIZE;
  73.     }
  74.     cop = call_list_free;
  75.     call_list_free = call_list_free->next;
  76.     cop->function = string_copy(fun);
  77.     cop->command_giver = command_giver; /* save current player context */
  78.     if (command_giver)
  79.     add_ref(command_giver, "new_call_out");        /* Bump its ref */
  80.     cop->ob = ob;
  81.     add_ref(ob, "call_out");
  82.     cop->v.type = T_NUMBER;
  83.     cop->v.u.number = 0;
  84.     if (arg)
  85.     assign_svalue(&cop->v, arg);
  86.     for (copp = &call_list; *copp; copp = &(*copp)->next) {
  87.     if ((*copp)->delta >= delay) {
  88.         (*copp)->delta -= delay;
  89.         cop->delta = delay;
  90.         cop->next = *copp;
  91.         *copp = cop;
  92.         return;
  93.     }
  94.     delay -= (*copp)->delta;
  95.     }
  96.     *copp = cop;
  97.     cop->delta = delay;
  98.     cop->next = 0;
  99. }
  100.  
  101. /*
  102.  * See if there are any call outs to be called. Set the 'command_giver'
  103.  * if it is a living object. Check for shadowing objects, which may also
  104.  * be living objects.
  105.  */
  106. void call_out() {
  107.     struct call *cop;
  108.     jmp_buf save_error_recovery_context;
  109.     int save_rec_exists;
  110.     struct object *save_command_giver;
  111.     extern struct object *command_giver;
  112.     extern struct object *current_interactive;
  113.     extern int current_time;
  114.     static int last_time;
  115.  
  116.     if (call_list == 0) {
  117.     last_time = current_time;
  118.     return;
  119.     }
  120.     if (last_time == 0)
  121.     last_time = current_time;
  122.     save_command_giver = command_giver;
  123.     current_interactive = 0;
  124.     call_list->delta -= current_time - last_time;
  125.     last_time = current_time;
  126.     memcpy((char *) save_error_recovery_context,
  127.        (char *) error_recovery_context, sizeof error_recovery_context);
  128.     save_rec_exists = error_recovery_context_exists;
  129.     error_recovery_context_exists = 1;
  130.     while (call_list && call_list->delta <= 0) {
  131.     /*
  132.      * Move the first call_out out of the chain.
  133.      */
  134.     cop = call_list;
  135.     call_list = call_list->next;
  136.     /*
  137.      * A special case:
  138.      * If a lot of time has passed, so that current call out was missed,
  139.      * then it will have a negative delta. This negative delta implies
  140.      * that the next call out in the list has to be adjusted.
  141.      */
  142.     if (call_list && cop->delta < 0)
  143.         call_list->delta += cop->delta;
  144.     if (!(cop->ob->flags & O_DESTRUCTED)) {
  145.         if (setjmp(error_recovery_context)) {
  146.         extern void clear_state();
  147.         clear_state();
  148.         debug_message("Error in call out.\n");
  149.         } else {
  150.         struct svalue v;
  151.         struct object *ob;
  152.  
  153.         ob = cop->ob;
  154.         while(ob->shadowing)
  155.             ob = ob->shadowing;
  156.         command_giver = 0;
  157.         if (cop->command_giver &&
  158.             !(cop->command_giver->flags & O_DESTRUCTED))
  159.         {
  160.             command_giver = cop->command_giver;
  161.         } else if (ob->flags & O_ENABLE_COMMANDS) {
  162.             command_giver = ob;
  163.         }
  164.         v.type = cop->v.type;
  165.         v.u = cop->v.u;
  166.         v.string_type = cop->v.string_type;    /* Not always used */
  167.         if (v.type == T_OBJECT && (v.u.ob->flags & O_DESTRUCTED)) {
  168.             v.type = T_NUMBER;
  169.             v.u.number = 0;
  170.         }
  171.         push_svalue(&v);
  172.         (void)apply(cop->function, cop->ob, 1);
  173.         }
  174.     }
  175.     free_call(cop);
  176.     }
  177.     memcpy((char *) error_recovery_context,
  178.        (char *) save_error_recovery_context,
  179.        sizeof error_recovery_context);
  180.     error_recovery_context_exists = save_rec_exists;
  181.     command_giver = save_command_giver;
  182. }
  183.  
  184. /*
  185.  * Throw away a call out. First call to this function is discarded.
  186.  * The time left until execution is returned.
  187.  * -1 is returned if no call out pending.
  188.  */
  189. int remove_call_out(ob, fun)
  190.     struct object *ob;
  191.     char *fun;
  192. {
  193.     struct call **copp, *cop;
  194.     int delay = 0;
  195.  
  196.     for (copp = &call_list; *copp; copp = &(*copp)->next) {
  197.     delay += (*copp)->delta;
  198.     if ((*copp)->ob == ob && strcmp((*copp)->function, fun) == 0) {
  199.         cop = *copp;
  200.         if (cop->next)
  201.         cop->next->delta += cop->delta;
  202.         *copp = cop->next;
  203.         free_call(cop);
  204.         return delay;
  205.     }
  206.     }
  207.     return -1;
  208. }
  209.  
  210. int find_call_out(ob, fun)
  211.     struct object *ob;
  212.     char *fun;
  213. {
  214.     struct call **copp;
  215.     int delay = 0;
  216.     for (copp = &call_list; *copp; copp = &(*copp)->next) {
  217.     delay += (*copp)->delta;
  218.     if ((*copp)->ob == ob && strcmp((*copp)->function, fun) == 0) {
  219.         return delay;
  220.     }
  221.     }
  222.     return -1;
  223. }
  224.  
  225. int print_call_out_usage(verbose)
  226.     int verbose;
  227. {
  228.     int i;
  229.     struct call *cop;
  230.  
  231.     for (i=0, cop = call_list; cop; cop = cop->next)
  232.     i++;
  233.     if (verbose) {
  234.     add_message("\nCall out information:\n");
  235.     add_message("---------------------\n");
  236.     add_message("Number of allocated call outs: %8d, %8d bytes\n",
  237.             num_call, num_call * sizeof (struct call));
  238.     add_message("Current length: %d\n", i);
  239.     } else {
  240.     add_message("call out:\t\t\t%8d %8d (current length %d)\n", num_call,
  241.             num_call * sizeof (struct call), i);
  242.     }
  243.     return num_call * sizeof (struct call);
  244. }
  245.  
  246. #ifdef DEBUG
  247. void count_ref_from_call_outs()
  248. {
  249.     struct call *cop;
  250.  
  251.     for (cop = call_list; cop; cop = cop->next) {
  252.     switch(cop->v.type)
  253.     {
  254.         case T_POINTER:
  255.         cop->v.u.vec->extra_ref++;
  256.         break;
  257.         case T_OBJECT:
  258.         cop->v.u.ob->extra_ref++;
  259.         break;
  260.     }
  261.     cop->ob->extra_ref++;
  262.     }
  263. }
  264. #endif
  265.  
  266. /*
  267.  * Construct an array of all pending call_outs. Every item in the array
  268.  * consists of 4 items (but only if the object not is destructed):
  269.  * 0:    The object.
  270.  * 1:    The function (string).
  271.  * 2:    The delay.
  272.  * 3:    The argument.
  273.  */
  274. struct vector *get_all_call_outs() {
  275.     int i, next_time;
  276.     struct call *cop;
  277.     struct vector *v;
  278.  
  279.     for (i=0, cop = call_list; cop; i++, cop = cop->next)
  280.     ;
  281.     v = allocate_array(i);
  282.     next_time = 0;
  283.     /*
  284.      * Take for granted that all items in an array are initialized to
  285.      * number 0.
  286.      */
  287.     for (i=0, cop = call_list; cop; i++, cop = cop->next) {
  288.     struct vector *vv;
  289.  
  290.     next_time += cop->delta;
  291.     if (cop->ob->flags & O_DESTRUCTED)
  292.         continue;
  293.     vv = allocate_array(4);
  294.     vv->item[0].type = T_OBJECT;
  295.     vv->item[0].u.ob = cop->ob;
  296.     add_ref(cop->ob, "get_all_call_outs");
  297.     vv->item[1].type = T_STRING;
  298.     vv->item[1].string_type = STRING_SHARED;
  299.     vv->item[1].u.string = make_shared_string(cop->function);
  300.     vv->item[2].u.number = next_time;
  301.     assign_svalue_no_free(&vv->item[3], &cop->v);
  302.  
  303.     v->item[i].type = T_POINTER;
  304.     v->item[i].u.vec = vv;        /* Ref count is already 1 */
  305.     }
  306.     return v;
  307. }
  308.